From: Keir Fraser Date: Mon, 7 Sep 2009 07:44:50 +0000 (+0100) Subject: vt-d: enhance the support of Interrupt Remapping EIM and x2APIC X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~13373 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/success//%22http:/www.example.com/cgi/success/?a=commitdiff_plain;h=cda2f6c76132090176f4b88c84917861c21bd21c;p=xen.git vt-d: enhance the support of Interrupt Remapping EIM and x2APIC 1) Clear Interrupt Remapping(IR) unit's CFI (Compatibility Format Interrupt) to enhance security; 2) Move the iommu_setup() ahead and put it before we begin to use IOAPIC so we can make sure after we enable Interrupt Remapping, the later IOAPIC (and MSI) initialization would setup IOAPIC RTEs (and MSI) with remappable format; 3) Enable x2APIC only when all VT-d engines support IR with EIM (Extended Interrupt Mode). EIM enables external devices to deliver interrupts to logical processor with >8-bit APIC ID. Signed-off-by: Dexuan Cui --- diff --git a/xen/arch/ia64/xen/xensetup.c b/xen/arch/ia64/xen/xensetup.c index 579fe3c861..da8de417c2 100644 --- a/xen/arch/ia64/xen/xensetup.c +++ b/xen/arch/ia64/xen/xensetup.c @@ -630,6 +630,8 @@ printk("num_online_cpus=%d, max_cpus=%d\n",num_online_cpus(),max_cpus); initialise_gdb(); /* could be moved earlier */ + iommu_setup(); /* setup iommu if available */ + do_initcalls(); sort_main_extable(); diff --git a/xen/arch/x86/apic.c b/xen/arch/x86/apic.c index b0d6392cda..47d614269e 100644 --- a/xen/arch/x86/apic.c +++ b/xen/arch/x86/apic.c @@ -848,6 +848,9 @@ void enable_x2apic(void) { u32 lo, hi; + if ( !iommu_supports_eim() ) + return; + rdmsr(MSR_IA32_APICBASE, lo, hi); if ( !(lo & MSR_IA32_APICBASE_EXTD) ) { @@ -858,7 +861,13 @@ void enable_x2apic(void) else printk("x2APIC mode enabled by BIOS.\n"); - x2apic_enabled = 1; + if ( !x2apic_enabled ) + { + x2apic_enabled = 1; + genapic = &apic_x2apic; + printk(KERN_INFO "Switched to APIC driver %s.\n", + genapic->name); + } } void __init init_apic_mappings(void) @@ -889,6 +898,8 @@ __next: */ if (boot_cpu_physical_apicid == -1U) boot_cpu_physical_apicid = get_apic_id(); + x86_cpu_to_apicid[0] = get_apic_id(); + cpu_2_logical_apicid[0] = get_logical_apic_id(); init_ioapic_mappings(); } diff --git a/xen/arch/x86/genapic/probe.c b/xen/arch/x86/genapic/probe.c index 295037e8cf..eaf1df24c7 100644 --- a/xen/arch/x86/genapic/probe.c +++ b/xen/arch/x86/genapic/probe.c @@ -14,7 +14,6 @@ #include #include -extern struct genapic apic_x2apic; extern struct genapic apic_summit; extern struct genapic apic_bigsmp; extern struct genapic apic_default; @@ -22,7 +21,6 @@ extern struct genapic apic_default; struct genapic *genapic; struct genapic *apic_probe[] __initdata = { - &apic_x2apic, &apic_summit, &apic_bigsmp, &apic_default, /* must be last */ diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 26bf8503a4..6518152985 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -904,11 +904,11 @@ void __init __start_xen(unsigned long mbi_p) generic_apic_probe(); + acpi_boot_init(); + if ( x2apic_is_available() ) enable_x2apic(); - acpi_boot_init(); - init_cpu_to_node(); if ( smp_found_config ) @@ -954,6 +954,8 @@ void __init __start_xen(unsigned long mbi_p) if ( opt_nosmp ) max_cpus = 0; + iommu_setup(); /* setup iommu if available */ + smp_prepare_cpus(max_cpus); spin_debug_enable(); diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c index c6906871d7..6a32dcd84f 100644 --- a/xen/drivers/passthrough/iommu.c +++ b/xen/drivers/passthrough/iommu.c @@ -260,7 +260,7 @@ int deassign_device(struct domain *d, u8 bus, u8 devfn) return 0; } -static int iommu_setup(void) +int iommu_setup(void) { int rc = -ENODEV; @@ -279,7 +279,6 @@ static int iommu_setup(void) iommu_pv_enabled ? "en" : "dis"); return rc; } -__initcall(iommu_setup); int iommu_get_device_group(struct domain *d, u8 bus, u8 devfn, XEN_GUEST_HANDLE_64(uint32) buf, int max_sdevs) diff --git a/xen/drivers/passthrough/vtd/dmar.c b/xen/drivers/passthrough/vtd/dmar.c index fbbc30204f..4386149ac9 100644 --- a/xen/drivers/passthrough/vtd/dmar.c +++ b/xen/drivers/passthrough/vtd/dmar.c @@ -357,6 +357,7 @@ acpi_parse_one_drhd(struct acpi_dmar_entry_header *header) struct acpi_table_drhd * drhd = (struct acpi_table_drhd *)header; void *dev_scope_start, *dev_scope_end; struct acpi_drhd_unit *dmaru; + void *addr; int ret = 0; static int include_all = 0; @@ -371,6 +372,9 @@ acpi_parse_one_drhd(struct acpi_dmar_entry_header *header) dprintk(XENLOG_INFO VTDPREFIX, "dmaru->address = %"PRIx64"\n", dmaru->address); + addr = map_to_nocache_virt(0, drhd->address); + dmaru->ecap = dmar_readq(addr, DMAR_ECAP_REG); + dev_scope_start = (void *)(drhd + 1); dev_scope_end = ((void *)drhd) + header->length; ret = acpi_parse_dev_scope(dev_scope_start, dev_scope_end, diff --git a/xen/drivers/passthrough/vtd/dmar.h b/xen/drivers/passthrough/vtd/dmar.h index bed177adc6..105b2beb31 100644 --- a/xen/drivers/passthrough/vtd/dmar.h +++ b/xen/drivers/passthrough/vtd/dmar.h @@ -50,6 +50,7 @@ struct acpi_drhd_unit { struct dmar_scope scope; /* must be first member of struct */ struct list_head list; u64 address; /* register base address of the unit */ + u64 ecap; u8 include_all:1; struct iommu *iommu; struct list_head ioapic_list; @@ -109,6 +110,8 @@ do { \ } \ } while (0) +void *map_to_nocache_virt(int nr_iommus, u64 maddr); + int vtd_hw_check(void); void disable_pmr(struct iommu *iommu); int is_usb_device(u8 bus, u8 devfn); diff --git a/xen/drivers/passthrough/vtd/intremap.c b/xen/drivers/passthrough/vtd/intremap.c index 47350732b8..1d1840d26a 100644 --- a/xen/drivers/passthrough/vtd/intremap.c +++ b/xen/drivers/passthrough/vtd/intremap.c @@ -121,6 +121,22 @@ static void set_ioapic_source_id(int apic_id, struct iremap_entry *ire) apicid_to_bdf(apic_id)); } +int iommu_supports_eim(void) +{ + struct acpi_drhd_unit *drhd; + + if ( !iommu_enabled || !iommu_qinval || !iommu_intremap ) + return 0; + + for_each_drhd_unit ( drhd ) + if ( !ecap_queued_inval(drhd->ecap) || + !ecap_intr_remap(drhd->ecap) || + !ecap_eim(drhd->ecap) ) + return 0; + + return 1; +} + static int remap_entry_to_ioapic_rte( struct iommu *iommu, struct IO_xAPIC_route_entry *old_rte) { @@ -635,10 +651,10 @@ int enable_intremap(struct iommu *iommu) ir_ctrl->iremap_index = -1; } -#if defined(ENABLED_EXTENDED_INTERRUPT_SUPPORT) +#ifdef CONFIG_X86 /* set extended interrupt mode bit */ ir_ctrl->iremap_maddr |= - ecap_ext_intr(iommu->ecap) ? (1 << IRTA_REG_EIME_SHIFT) : 0; + x2apic_enabled ? (1 << IRTA_REG_EIME_SHIFT) : 0; #endif spin_lock_irqsave(&iommu->register_lock, flags); @@ -659,13 +675,6 @@ int enable_intremap(struct iommu *iommu) iommu_flush_iec_global(iommu); spin_lock_irqsave(&iommu->register_lock, flags); - /* enable comaptiblity format interrupt pass through */ - gcmd |= DMA_GCMD_CFI; - dmar_writel(iommu->reg, DMAR_GCMD_REG, gcmd); - - IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl, - (sts & DMA_GSTS_CFIS), sts); - /* enable interrupt remapping hardware */ gcmd |= DMA_GCMD_IRE; dmar_writel(iommu->reg, DMAR_GCMD_REG, gcmd); diff --git a/xen/drivers/passthrough/vtd/iommu.h b/xen/drivers/passthrough/vtd/iommu.h index bcb05dc5f9..2d979dbd65 100644 --- a/xen/drivers/passthrough/vtd/iommu.h +++ b/xen/drivers/passthrough/vtd/iommu.h @@ -101,7 +101,7 @@ #define ecap_queued_inval(e) ((e >> 1) & 0x1) #define ecap_dev_iotlb(e) ((e >> 2) & 0x1) #define ecap_intr_remap(e) ((e >> 3) & 0x1) -#define ecap_ext_intr(e) ((e >> 4) & 0x1) +#define ecap_eim(e) ((e >> 4) & 0x1) #define ecap_cache_hints(e) ((e >> 5) & 0x1) #define ecap_pass_thru(e) ((e >> 6) & 0x1) #define ecap_snp_ctl(e) ((e >> 7) & 0x1) diff --git a/xen/drivers/passthrough/vtd/vtd.h b/xen/drivers/passthrough/vtd/vtd.h index 18e87bef06..b81e5b42d6 100644 --- a/xen/drivers/passthrough/vtd/vtd.h +++ b/xen/drivers/passthrough/vtd/vtd.h @@ -100,7 +100,6 @@ struct msi_msg_remap_entry { unsigned int get_cache_line_size(void); void cacheline_flush(char *); void flush_all_cache(void); -void *map_to_nocache_virt(int nr_iommus, u64 maddr); u64 alloc_pgtable_maddr(struct acpi_drhd_unit *drhd, unsigned long npages); void free_pgtable_maddr(u64 maddr); void *map_vtd_domain_page(u64 maddr); diff --git a/xen/include/asm-x86/genapic.h b/xen/include/asm-x86/genapic.h index b860d2f511..2eef80e23e 100644 --- a/xen/include/asm-x86/genapic.h +++ b/xen/include/asm-x86/genapic.h @@ -49,6 +49,7 @@ struct genapic { APICFUNC(acpi_madt_oem_check) extern struct genapic *genapic; +extern struct genapic apic_x2apic; void init_apic_ldr_flat(void); void clustered_apic_check_flat(void); diff --git a/xen/include/asm-x86/smp.h b/xen/include/asm-x86/smp.h index 4abfb42fac..8cd15e2efb 100644 --- a/xen/include/asm-x86/smp.h +++ b/xen/include/asm-x86/smp.h @@ -49,6 +49,7 @@ extern void zap_low_mappings(l2_pgentry_t *base); #define MAX_APICID 256 extern u32 x86_cpu_to_apicid[]; +extern u32 cpu_2_logical_apicid[]; #define cpu_physical_id(cpu) x86_cpu_to_apicid[cpu] diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h index 402914d603..fe27141c1e 100644 --- a/xen/include/xen/iommu.h +++ b/xen/include/xen/iommu.h @@ -57,6 +57,9 @@ struct iommu { struct intel_iommu *intel; }; +int iommu_setup(void); +int iommu_supports_eim(void); + int iommu_add_device(struct pci_dev *pdev); int iommu_remove_device(struct pci_dev *pdev); int iommu_domain_init(struct domain *d);